package com.nebula.dao.impl;

import com.nebula.dao.IBaseDao;
import com.nebula.dao.Database;
import com.nebula.util.NamedUtil;


import java.io.Serializable;
import java.lang.reflect.*;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * @author CcccX
 * @create 2019-01-08 14:02
 */
public class BaseDaoImpl<T> implements IBaseDao<T> {
    private Class<?> clazz;
    
    public BaseDaoImpl() {
        Class clazz = this.getClass();
        ParameterizedType parameterizedType = (ParameterizedType) clazz.getGenericSuperclass();
        Type[] types = parameterizedType.getActualTypeArguments();
        this.clazz = (Class) types[0];
    }
    
    @Override
    public int save(T t) {
        //获取所有字段
        try {
            Field[] fields = clazz.getDeclaredFields();
            
            StringBuilder sql = new StringBuilder("insert into " + clazz.getSimpleName().toLowerCase() + "(");
            StringBuilder conditions = new StringBuilder("values(");
            Object[] values = new Object[fields.length];
            int i = 0;
            for (Field field : fields) {
                try {
                    sql.append(NamedUtil.camelToUnderline(field.getName())).append(", ");
                    field.setAccessible(true);
                    values[i] = (Object) field.get(t);
                    i++;
                } catch (Exception e) {
                    e.printStackTrace();
                }
                conditions.append("?, ");
            }
            conditions.setLength(conditions.toString().trim().length() - 1);
            sql.setLength(sql.toString().trim().length() - 1);
            sql.append(") ").append(conditions).append(")");
            return (int) Database.excute(sql.toString(), values);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            Database.close();
        }
        return -1;
    }
    
    @Override
    public int delete(Serializable id) {
        try {
            String sql = "delete from " + clazz.getSimpleName().toLowerCase() + " where id = ?";
            return (int) Database.excute(sql, new Object[]{(Object) id});
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            Database.close();
        }
        return -1;
    }
    
    @Override
    public int update(T t) {
        //获取所有字段
        try {
            Field[] fields = clazz.getDeclaredFields();
            StringBuilder sql = new StringBuilder("update " + clazz.getSimpleName().toLowerCase() + " set ");
            List<Object> list = new ArrayList<>();
            String id = "";
            for (Field field : fields) {
                try {
                    field.setAccessible(true);
                    if ("updatedtime".equals(field.getName().toLowerCase()) && field.get(t) == null) {
                        field.set(t, new Date());
                    }
                    if (field.get(t) != null && !"id".equals(field.getName().toLowerCase())) {
                        sql.append(NamedUtil.camelToUnderline(field.getName())).append("=?, ");
                        list.add((Object) field.get(t));
                    } else if ("id".equals(field.getName().toLowerCase())) {
                        id = String.valueOf(field.get(t));
                    }
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
            list.add(id);
            sql.setLength(sql.toString().trim().length() - 1);
            sql.append(" where id=?");
            return (int) Database.excute(sql.toString(), list.toArray());
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            Database.close();
        }
        
        return -1;
    }
    
    @Override
    public T findById(Serializable id) {
        //获取所有字段
        Field[] fields = clazz.getDeclaredFields();
        StringBuilder sql = new StringBuilder("select ");
        T t = null;
        try {
            t = (T) clazz.newInstance();
            for (Field field : fields) {
                sql.append(NamedUtil.camelToUnderline(field.getName())).append(", ");
            }
            sql.setLength(sql.toString().trim().length() - 1);
            sql.append(" from ").append(clazz.getSimpleName().toLowerCase()).append(" where id=?");
            ResultSet rs = (ResultSet) Database.excute(sql.toString(), id);
            if (rs != null) {
                while (rs.next()) {
                    for (Field field : fields) {
                        field.setAccessible(true);
                        field.set(t, rs.getObject(NamedUtil.camelToUnderline(field.getName())));
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return t;
    }
    
    @Override
    public List<T> findAll() {
        //获取所有字段
        Field[] fields = clazz.getDeclaredFields();
        StringBuilder sql = new StringBuilder("select ");
        T t = null;
        List<T> tList = new ArrayList<>();
        try {
            for (Field field : fields) {
                sql.append(NamedUtil.camelToUnderline(field.getName())).append(", ");
            }
            sql.setLength(sql.toString().trim().length() - 1);
            sql.append(" from ").append(clazz.getSimpleName().toLowerCase());
            ResultSet rs = (ResultSet) Database.excute(sql.toString());
            setMethod(fields, (List<T>) tList, rs);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return tList;
    }
    
    @Override
    public List<T> findByPage(Integer currPage, Integer pageSize, java.lang.Object... conditions) {
        //获取所有字段
        Field[] fields = clazz.getDeclaredFields();
        StringBuilder sql = new StringBuilder("select ");
        T t = null;
        List<T> tList = new ArrayList<>();
        try {
            for (Field field : fields) {
                sql.append(NamedUtil.camelToUnderline(field.getName())).append(", ");
            }
            sql.setLength(sql.toString().trim().length() - 1);
            sql.append(" from ").append(clazz.getSimpleName().toLowerCase());
            sql = handle(sql.toString(), (Object[]) conditions);
            sql.append(" limit ").append((currPage - 1) * pageSize).append(", ").append(pageSize);
            ResultSet rs = (ResultSet) Database.excute(sql.toString());
            setMethod(fields, (List<T>) tList, rs);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return tList;
    }
    
    @Override
    public int selectCount(Serializable tableName, java.lang.Object... conditions) {
        String sql = "select count(1) from " + tableName;
        sql = String.valueOf(handle(sql, (Object[]) conditions));
        ResultSet rs = (ResultSet) Database.excute(sql);
        int totalCount = 0;
        totalCount = getResultCount(totalCount, rs);
        return totalCount;
    }
    
    @Override
    public boolean checkNavRole(int roleId, String navId) {
        boolean flag = false;
        String sql = "select count(1) from role_navigation where nav_id = ? and role_id = ?";
        ResultSet rs = (ResultSet) Database.excute(sql, new Object[]{navId, roleId});
        try {
            if (rs != null) {
                while (rs.next()) {
                    flag = rs.getInt(1) > 0;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return flag;
    }
    
    static int getResultCount(int resultCount, ResultSet rs) {
        try {
            if (rs != null) {
                while (rs.next()) {
                    resultCount = rs.getInt(1);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return resultCount;
    }
    
    private void setMethod(Field[] fields, List<T> tList, ResultSet rs) throws SQLException, InstantiationException, IllegalAccessException {
        T t;
        if (rs != null) {
            while (rs.next()) {
                t = (T) clazz.newInstance();
                for (Field field : fields) {
                    field.setAccessible(true);
                    field.set(t, rs.getObject(NamedUtil.camelToUnderline(field.getName())));
                }
                tList.add(t);
            }
        }
    }
    
    private static StringBuilder handle(String sql, Object[] objects) {
        StringBuilder sqlBuilder = new StringBuilder(sql);
        if (objects != null) {
            for (Object object : objects) {
                sqlBuilder.append(" ").append(object).append(" ");
            }
        }
        return sqlBuilder;
    }

    /*private static final char UNDERLINE = '_';

    private String assembleGetSetMethod(String filedName, String getOrSet) {
        if (StringUtils.isBlank(filedName)) {
            return null;
        }
        if (StringUtils.isBlank(getOrSet)) {
            getOrSet = "get";
        }
        int startIndex = 0;
        if (filedName.charAt(0) == UNDERLINE) {
            startIndex = 1;
        }
        return getOrSet
                + filedName.substring(startIndex, startIndex + 1).toUpperCase()
                + filedName.substring(startIndex + 1);
    }*/
}
